package com.meilingcloud.biobank.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.meilingcloud.biobank.domain.Container;
import com.meilingcloud.biobank.domain.GeneralQuery;
import com.meilingcloud.biobank.domain.SampleBackup;
import com.meilingcloud.biobank.domain.Tube;
import com.meilingcloud.biobank.domain.dto.GeneralQueryDto;
import com.meilingcloud.biobank.domain.dto.GeneralQueryParamDto;
import com.meilingcloud.biobank.domain.vo.GeneralQueryParamVo;
import com.meilingcloud.biobank.mapper.SampleBackupMapper;
import com.meilingcloud.biobank.service.IContainerService;
import com.meilingcloud.biobank.service.IGeneralQueryService;
import com.meilingcloud.biobank.service.ITubeService;
import com.meilingcloud.common.enums.CalculateType;
import com.meilingcloud.system.domain.SysCustomForm;
import com.meilingcloud.system.service.ISysCustomFormService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;

@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Service
public class GeneralQueryService implements IGeneralQueryService {

    private final ISysCustomFormService customFormService;
    private final IContainerService containerService;
    private final ITubeService tubeService;
    private final SampleBackupMapper sampleBackupMapper;

    @Override
    public List<GeneralQueryParamVo> getQueryParams(GeneralQueryParamDto dto) {
        List<GeneralQueryParamVo> paramVos = new ArrayList<>();
        if (dto.getLevel() == 0) {
            getFirstLevel(paramVos);
        } else if (dto.getLevel() == 1) {
            getSecondLevel(paramVos, dto);
        } else if (dto.getLevel() == 2) {
            getThirdLevel(paramVos);
        }
        return paramVos;
    }

    private void getThirdLevel(List<GeneralQueryParamVo> paramVos) {
        EnumSet.allOf(CalculateType.class).forEach(item -> {
            GeneralQueryParamVo vo = new GeneralQueryParamVo();
            vo.setValue(item.getCode());
            vo.setLabel(item.getInfo());
            vo.setLeaf(true);
            paramVos.add(vo);
        });
    }

    private void getSecondLevel(List<GeneralQueryParamVo> paramVos, GeneralQueryParamDto dto) {
        SysCustomForm customForm = customFormService.getByKey(dto.getValue());
        if (ObjectUtil.isNotEmpty(customForm)) {
            JSONObject jsonObject = JSONObject.parseObject(customForm.getFormJson());
            JSONArray jsonArray = jsonObject.getJSONArray("fields");
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject object = jsonArray.getJSONObject(i);
                JSONObject confObj = object.getJSONObject("__config__");
                if (ObjectUtil.isNotEmpty(confObj.getJSONArray("children"))) {
                    JSONArray children = confObj.getJSONArray("children");
                    for (int j = 0; j < children.size(); j++) {
                        JSONObject child = children.getJSONObject(j);
                        JSONObject childObj = child.getJSONObject("__config__");
                        GeneralQueryParamVo vo = new GeneralQueryParamVo();
                        vo.setValue(child.getString("__vModel__"));
                        vo.setLabel(childObj.getString("label"));
                        paramVos.add(vo);
                    }
                } else {
                    GeneralQueryParamVo vo = new GeneralQueryParamVo();
                    vo.setValue(object.getString("__vModel__"));
                    vo.setLabel(confObj.getString("label"));
                    paramVos.add(vo);
                }
            }
        }
    }

    private void getFirstLevel(List<GeneralQueryParamVo> paramVos) {
        List<SysCustomForm> customForms = customFormService.list();
        List<GeneralQueryParamVo> collect = customForms.stream().map(item -> {
            GeneralQueryParamVo vo = new GeneralQueryParamVo();
            vo.setValue(item.getFormKey());
            vo.setLabel(item.getFormName());
            return vo;
        }).collect(Collectors.toList());
        paramVos.addAll(collect);
    }

    @Override
    public GeneralQuery handleGeneralQuery(GeneralQueryDto dto) {
        GeneralQuery generalQuery = new GeneralQuery();
        BeanUtil.copyProperties(dto, generalQuery);

        if (CollectionUtil.isNotEmpty(dto.getConditions())) {
            List<String> formKeys = dto.getConditions().stream()
                    .filter(item -> CollectionUtil.isNotEmpty(item.getOdds()) && StringUtils.isNotBlank(item.getOdds().get(0)))
                    .map(item -> item.getOdds().get(0)).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(formKeys)) {
                List<SysCustomForm> sysCustomForms = customFormService.list(new LambdaQueryWrapper<SysCustomForm>().in(SysCustomForm::getFormKey, formKeys));
                dto.getConditions().forEach(item -> {
                    if (CollectionUtil.isEmpty(item.getOdds()) || StringUtils.isBlank(item.getValue())) {
                        return;
                    }
                    if (CollectionUtil.isEmpty(generalQuery.getConditions())) {
                        generalQuery.setConditions(new ArrayList<>());
                    }
                    GeneralQuery.Condition condition = new GeneralQuery.Condition();
                    condition.setFormKey(item.getOdds().get(0));
                    sysCustomForms.forEach(cf -> {
                        if (StringUtils.equals(cf.getFormKey(), item.getOdds().get(0))) {
                            condition.setType(cf.getFormType());
                        }
                    });
                    condition.setOdd("$." + item.getOdds().get(1));
                    condition.setWay(item.getOdds().get(2));
                    if (StringUtils.equalsIgnoreCase(condition.getWay(), CalculateType.FUZZY_MATCH.getCode())) {
                        condition.setValue("'%" + item.getValue() + "%'");
                    } else {
                        condition.setValue(item.getValue());
                    }
                    generalQuery.getConditions().add(condition);
                });
            }
        }
        if (CollectionUtil.isNotEmpty(dto.getContainers())) {
            List<Long> sampBackupIds = new ArrayList<>();
            dto.getContainers().forEach(item -> {
                List<Container> containers = new ArrayList<>();
                if (ObjectUtil.isNotNull(item.getBoxRow()) && ObjectUtil.isNotNull(item.getBoxColumn())) {
                    containers.add(item);
                } else {
                    containers.addAll(containerService.getLeafByParent(item.getContainerId()));
                }
                if (CollectionUtil.isNotEmpty(containers)) {
                    List<Long> containerIds = containers.stream().map(Container::getContainerId).collect(Collectors.toList());
                    List<Tube> tubes = tubeService.list(new LambdaQueryWrapper<Tube>().gt(Tube::getSampBackupId, 0)
                            .in(Tube::getContainerId, containerIds));
                    if (CollectionUtil.isNotEmpty(tubes)) {
                        List<Long> ids = tubes.stream().map(Tube::getSampBackupId).collect(Collectors.toList());
                        sampBackupIds.addAll(ids);
                    }
                }
            });
            generalQuery.setSampBackupIds(sampBackupIds);
        }
        if (CollectionUtil.isNotEmpty(dto.getSamplingRange())) {
            generalQuery.setSamplingStart(dto.getSamplingRange().get(0));
            generalQuery.setSamplingEnd(dto.getSamplingRange().get(1));
        }
        return generalQuery;
    }

    @Override
    public List<SampleBackup> queryList(GeneralQuery query) {
        if (null != query.getSampBackupIds() && query.getSampBackupIds().size() == 0) {
            return new ArrayList<>();
        }
        return sampleBackupMapper.generalQueryList(query);
    }

    @Override
    public List<SampleBackup> fuzzyQueryList(String keyword) {
        return sampleBackupMapper.fuzzyQueryList(keyword);
    }

}
